The DateToken add, divide, modulo, multiply and subtract methods now all throw exceptions and have tests.

There are a number of reasons we have not had a DateToken that was convertable until now.

I fixed up the code so that if we call toString() on a DateToken and then parse the string, we get a DateToken equal to the first DateToken. The problem is that the toString() method of the java Date class does not include the value of the milliseconds. Also, the default java Date parser does not parse the output from toString(). This is now fixed.

I also added isGreater() and isLessThan() methods because Date has after() and before() methods.

A larger problem has to do with type conversion.

See below for the previous value of the convert() method in BaseType for the DateType, which converts from LongToken and StringToken to DateToken.

public Token convert(Token t) throws IllegalActionException {
            if (t instanceof DateToken) {
                return t;
            } else if (t instanceof LongToken) {
                return new DateToken(((LongToken) t).longValue());
            } else if (t instanceof StringToken) {
                return new DateToken(((StringToken) t).stringValue());
            }
            throw new IllegalActionException(
              Token.notSupportedIncomparableConversionMessage(t, "date"));
            }

At first cut, this seems right, but I think ignores conversions from anything below LongToken, such as IntToken. Also, not all StringTokens can be losslessly converted to DateTokens. So, I added the DateToken.convert(), which is similar to ScalarToken.convert.

I started working on this, but ran in to various issues. I added the following to TypeLattice so that we could convert from Long to Date:

_basicLattice.addEdge(BaseType.UNKNOWN, BaseType.DATE);
             _basicLattice.addEdge(BaseType.DATE, BaseType.STRING);
+ // Allowing a conversion from STRING to a DATE would make the lattice cyclic
+            //_basicLattice.addEdge(BaseType.STRING, BaseType.DATE);
+            _basicLattice.addEdge(BaseType.LONG, BaseType.DATE);

I added a convert() method to DateToken which seems to work well. I did hack in a check for StringToken which will try to instantiate a DateToken. I'm not sure if that is right.

public static DateToken convert(Token token) throws IllegalActionException {
        if (token instanceof DateToken) {
            return (DateToken) token;
        }

        if (token.isNil()) {
            return DateToken.NIL;
        }

        int compare = TypeLattice.compare(BaseType.DATE, token);

        if (compare == CPO.LOWER || compare == CPO.INCOMPARABLE) {
            // This seems really wrong, but we want to be able to
            // convert from a StringToken to a DateToken.
            if (token instanceof StringToken) {
                return new DateToken(((StringToken) token).stringValue());
            }
            throw new IllegalActionException(
notSupportedIncomparableConversionMessage(token, "date"));
        }

        compare = TypeLattice.compare(BaseType.LONG, token);

        if (compare == CPO.SAME || compare == CPO.HIGHER) {
            LongToken longToken = LongToken.convert(token);
            DateToken result = new DateToken(longToken.longValue());
            return result;
        }
        compare = TypeLattice.compare(BaseType.STRING, token);

        if (compare == CPO.SAME || compare == CPO.HIGHER) {
            StringToken stringToken = StringToken.convert(token);
            DateToken result = new DateToken(stringToken.stringValue());
            return result;
        }

throw new IllegalActionException(notSupportedConversionMessage(token,
                "date"));
    }


Where I ran in to problems is adding code to allow the comparison of two DateTokens.

Right now, this test fails where I try to call DateToken.isGreaterThan() on a LongToken
==== $PTII/ptolemy/data/test/DateToken.tcl: DateToken-9.1 Test isGreaterThan with other types
==== Contents of test case:

    set long1 [java::new {ptolemy.data.LongToken long} 1]
    set int1 [java::new {ptolemy.data.IntToken int} 1]
    set short1 [java::new {ptolemy.data.ShortToken short} 1]

    set t2 [java::new {ptolemy.data.DateToken long} 2]
    list [[$t2 isGreaterThan $long1] toString]

    #list [[$t2 isGreaterThan $int1] toString]
    #[[$t2 isGreaterThan $short1] toString]


==== Test generated error:
    while executing
java.lang.ClassCastException: ptolemy.data.StringToken cannot be cast to ptolemy.data.PartiallyOrderedToken
        at ptolemy.data.DateToken.isGreaterThan(DateToken.java:226)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

I'm not totally sure why the LongToken is getting converted to a StringToken?

In the code below TypeLattice.compare(getType(), (Token)rightArgument) is returning CPO.HIGHER and then the convert line is converting to a StringToken?

I'm lost.

line 226 is marked with --->
public final BooleanToken isGreaterThan(PartiallyOrderedToken rightArgument)
            throws IllegalActionException {
        // Similar to the same method in ScalarToken.
int typeInfo = TypeLattice.compare(getType(), (Token)rightArgument);

        if (typeInfo == CPO.SAME) {
            return ((DateToken)rightArgument)._doIsLessThan(this);
        } else if (typeInfo == CPO.HIGHER) {
// This line is different from ScalarToken and causes problems with StringTokens. ----> PartiallyOrderedToken convertedArgument = (PartiallyOrderedToken) getType().convert((Token)rightArgument);
            try {
                return convertedArgument.isLessThan(this);
            } catch (IllegalActionException ex) {
        // If the type-specific operation fails, then create a
        // better error message that has the types of the
        // arguments that were passed in.
        throw new IllegalActionException(null, ex, notSupportedMessage(
"isGreaterThan", (Token)this, (Token)rightArgument));
            }
        } else if (typeInfo == CPO.LOWER) {
            return rightArgument.isLessThan(this);
        } else {
throw new IllegalActionException(notSupportedIncomparableMessage( "isGreaterThan", (Token)this, (Token)rightArgument));
        }
    }

At this point, I need to move on.

I've left these tests as failures for the time being, perhaps someone can look at this?


Bottom line: adding a type to the type lattice is not easy.

_Christopher

On 6/23/14 3:36 AM, Edward A. LEE wrote:
Interesting questions about operations.

Without thinking about it too much:

- add doesn't make sense to me.  The sum of two dates is not a date.
Sum of a date and a long (or an int) does, however. That is a date.
Sum of a Date and a Time also makes sense to me... Though here, we
have to assume units for Time (seconds?).

- subtract of two Dates is also not a Date.  But it could be a London
or a Time.

Edward

---------
Edward A. Lee
EECS, UC Berkeley
[email protected]

On Jun 22, 2014, at 8:36 PM, Patricia Derler <[email protected]> wrote:

Christopher,

Yes, I used the DateToken in Kepler and changed it. Thank you for going through 
the code and fixing some of it. I tried to make a minimal version of the 
DateToken work but forgot to implement several methods. Also, I think you are 
right, the type lattice needs to be changed.

Patricia


On 6/22/14, 7:39 PM, Christopher Brooks wrote:
Hi Patricia,
I saw that you checked in ptolemy.data.DateToken, which is a copy of 
kepler/util/src/org/kepler/date/DateToken.java so that we can use DateToken in 
Ptolemy (outside of Kepler).  The biggest difference between the two is that 
the Ptolemy version is convertible from LongToken.

There was a FindBugs warning about ptolemy.dateToken.toString() returning null, 
so I fixed that.

I also added support for nil DateTokens, so that we can support missing data.  
The Kepler version probably does not support nil DateTokens.

I also added tests for some of the above operations. Unfortunately, Ptjacl does 
not handle longs very well, so writing Tcl unit tests is tricky.

The ptolemy.data.DateToken file was badly formatted, it could be that your 
Eclipse configuration is using tabs.  However, my guess is that the formatting 
issues were from the copy from Kepler.

A few open issues:

- In ptolemy.data.type.BaseType, we have:
/** The date data type. */
    public static class DateType extends BaseType {
        private DateType() {
            super(DateToken.class, "date");
        }

        public Token convert(Token t) throws IllegalActionException {
            if (t instanceof DateToken) {
                return t;
            } else if (t instanceof LongToken) {
                return new DateToken(((LongToken) t).longValue());
            } else if (t instanceof StringToken) {
                return new DateToken(((StringToken) t).stringValue());
            }
            throw new IllegalActionException(
Token.notSupportedIncomparableConversionMessage(t, "date"));
        }

        public int getTypeHash() {
            return 15;
    }
Isn't anything that is convertible to a LongToken losslessly acceptable here as 
well?

Isn't it possible to losslessly convert from a DateToken to a LongToken?  Will 
this mess up the lattice?

- In ptolemy.data.DateToken, you have an _isEqualTo() method and other methods, 
these are necessary because ptolemy.data.DateToken extends 
AbstractConvertibleToken.  However, there are a bunch of methods like _add(), 
_divide() etc. that have no method bodies.

- Certain operations, such as add, are clearly doable if the Dates are 
converted to longs and then added and then converted back to DateTokens.  I 
think _add() and _subtract() could be possible

- For _isCloseTo(token, double epsilon):     If we convert the two tokens to 
longs and the epsilon to a long, then this might make sense?   However, double 
is not losslessly convertible to long? Probably throw an IllegalActionException 
here.

- I'm not sure it makes sense to divide a date by another date, but dividing a 
date by a long makes a certain amount of sense maybe?  I dunno.

- Ditto with _multiply.

- _modulo of two Dates might make sense but is confusing and should probably 
throw an exception.

Does anyone have thoughts about the above?

_Christopher
_______________________________________________
Ptolemy maillist  -  [email protected]
http://chess.eecs.berkeley.edu/ptolemy/listinfo/ptolemy


--
Christopher Brooks, PMP                       University of California
Academic Program Manager & Software Engineer  US Mail: 337 Cory Hall
CHESS/iCyPhy/Ptolemy/TerraSwarm               Berkeley, CA 94720-1774
[email protected], 707.332.0670           (Office: 545Q Cory)

_______________________________________________
Kepler-dev mailing list
[email protected]
http://lists.nceas.ucsb.edu/kepler/mailman/listinfo/kepler-dev

Reply via email to