Unable to "Consult" assert(ed) 'time' data type - Exception r306 Unsupported interface 'time'

Discussions related to Visual Prolog
larryhoughton
Posts: 11
Joined: 4 Oct 2016 21:16

Unable to "Consult" assert(ed) 'time' data type - Exception r306 Unsupported interface 'time'

Unread post by larryhoughton » 8 Jul 2017 16:48

Hello,
I don't get it. The "time" data type "consult" works normally if I execute the "consult" before terminating the program instance that executes the assert and save to create my disk file.

However, if I restart the program and immediately execute "consult", to retrieve the disk file data, the exception below is thrown:
Exception in module: OneClass.exe
c:\program files (x86)\visual prolog 7.5\pfc\event\event4.pro(42) : error r306: Invalid object conversion from '<unknown>': unsupported interface 'time'


Everything in these scenarios (assert,save,consult) work as expected (including restarting the program and immediately executing a "consult") unless I am using the data type "time".

Note:
I am experimenting with using multiple classes in case that comes into play. Everything above happens in one class ("data") that gets instantiated before any of the failing code executes. Also all of the declarations are in the data class.

** Code snippets **
facts - availableFactDB
testTime : (time).

clauses
assert(testTime(time::new(2017,12,25,9,0,0)))
file::save ("availableFactsDB.dba",availableFactDB)
file::consult("availableFactsDB.dba",availableFactDB)

Any ideas?
Larry

Martin Meyer
VIP Member
Posts: 294
Joined: 14 Nov 2002 0:01

Unread post by Martin Meyer » 8 Jul 2017 21:47

Hello Larry,

time is an object type. What happens, when you save the fact database, is, that the addresses of the time objects are written to the file. And, when you restore the database by consult, you are reading back these addresses. However the objects are not there anymore at the addresses. VIP attempts to interprete the random crap, which is now in memory at these address, as time objects - that results in an exception.

To store and restore objects you have to serialize them. That is, you have code a routine, which saves the object's data, and another one, which reads the data back and (re-)creates the objects. The data of a time object can be obtained from property gmtTimeValue, and time objects can be (re-)created from it. So, it works for example like:

Code: Select all

class facts - availableFactDB     testTime : (time).   class predicates     saveTestTime : (string FileName). clauses     saveTestTime(Filename) :-         OutStream = outputStream_file::create(Filename, stream::binary),         try             foreach testTime(Time) do                 OutStream:write(Time:gmtTimeValue)             end foreach         finally             OutStream:close()         end try.   class predicates     consultTestTime : (string FileName). clauses     consultTestTime(Filename) :-         InStream = inputStream_file::openFile(Filename, stream::binary),         try             foreach InStream:repeatToEndOfStream() do                 GmtTimeValue = InStream:read(),                 Time = time::newFromGMT(GmtTimeValue),                 assert(testTime(Time))             end foreach         finally             InStream:close()         end try.   class predicates     displayTestTime : (). class facts     formatter : timeFormatter := timeFormatter::new(). clauses     displayTestTime() :-         foreach testTime(Time) do             Formated = formatter:formatDateTime(Time, "dddd MMM dd',' yyyy", " 'at' H:mm'"),             stdIO::write(Formated, '\n')         end foreach,         stdIO::write("===\n").   clauses     run() :-         assert(testTime(time::new(2017, 01, 05, 03, 00, 0))),         assert(testTime(time::new(2017, 12, 22, 09, 00, 0))),         assert(testTime(time::new(2017, 11, 23, 17, 00, 0))),         displayTestTime(),         saveTestTime("availableFactsDB.dba"),         retractAll(testTime(_)),         consultTestTime("availableFactsDB.dba"),         displayTestTime().
Regards Martin

Harrison Pratt
VIP Member
Posts: 304
Joined: 5 Nov 2000 0:01

Unread post by Harrison Pratt » 9 Jul 2017 13:03

Hi Martin,

Thanks for the very crisp tutorial on serializing -- something I'll need to know soon!

larryhoughton
Posts: 11
Joined: 4 Oct 2016 21:16

I want my cake and eat it too

Unread post by larryhoughton » 9 Jul 2017 19:35

Hi Martin,
Thanks for your quick response. My need is to keep track of possibly thousands of date/time db records along with their related attributes in a compound domain. I'm looking for some guidance here because the date/time storage and comparison methods will be critical to my program's performance.

I can see (now) that it would be simple enough to serialize the time objects for storage and retrieval, but it seems like a lot of processing whereas I suppose I could just as easily(?) store the date/time data as individual integers (e.g. mm/dd/yyyy/hh/mm).

Storing time as integers - Pros:
  • My data file time entries would be human readable.
    "Consult" would work on the stored integers
    avoid the overhead of serialization
Storing time as integers - Cons:
  • Without the time object, I don't get the time *methods (for date/time comparisons etc.).
    I inherit the overhead of making my own *"time methods".
*Cake and Eat it Too?
  • Save the date/time data as integers (e.g. mm/dd/yyyy/hh/mm)
    Create a new <time object> from the retrieved integer data and.....
    Again have the time object methods that I lost when saving the date/time as integers
Hopefully there is a known answer for my dilemma. My primary priority will be efficiency in retrieving and comparing dates/times.

Note:
I'm using "Save/Consult" now, but I will be moving to DB Chains once I get some of these fundamental issues sorted out.

Thanks in advance,
Larry

Martin Meyer
VIP Member
Posts: 294
Joined: 14 Nov 2002 0:01

Unread post by Martin Meyer » 10 Jul 2017 0:54

The values of domain gmtTimeValue are simply 64 bit numbers. Its declaration in class core is:

Code: Select all

domains     gmtTimeValue = unsigned64.
To invent your own date/times coded in integers is no good idea. It would cost you needless efforts. Better go with the flow and just rely on the rich choice of well tested functionalities in the time package.

Generally VIP and the pfc (Prolog Foundation Classes) are making extensive use of objects, it is not only time. When you want to store objects, serialization is inevitable. Do not see a dilemma there, it is just a standard programming technique. Maybe in a future version VIP will support automatic object serialization. But until that, write your own serialization code per object type that you want to store/restore.

When you have a large number of data sentences, but you are processing only some of them selectively, hold date/times in the gross of your data as gmtTimeValue numbers. When you pick up one data sentence from the gross for processing, 'unpack' it, i.e. construct the time object from the gmtTimeValue. That is more efficient than constructing the time objects of all data sentences right away.

When you are searching in larger amounts of data, do not store the data in a fact database, because that is slow. I suppose VIP just tries one fact after the other to find matches. Thus searching is in O(n) where n is the number of facts in the database.

Identify "keys" in your data. I.e. small sub-fields in your data containing the values, which you want to match in your searches. Typically keys are numbers containing person IDs, item IDs, date/time values, etc. or maybe strings containing names.

For searching data by a key collections based on trees (construct them for example from class mapM_redBlack{@Key, @Data}) offer a good runtime growth rate with respect to the number of items in the collection. Searching in a tree-based collection is in O(log(n)) (provided two keys can be compared in constant time). If your keys are positive numbers, use a collection based on an array (i.e. class arrayM{@ItemType}). Retrieval time then is even better, it is in O(1).

If you have very large amounts of data, consider using a database system like for example MariaDB via the ODBC package. But do not use the chainDB package. The package is kind of deprecated. Thomas said it is only still there for reasons of backwards compatibility. I guess he will kick it out in future VIP versions.
Regards Martin

larryhoughton
Posts: 11
Joined: 4 Oct 2016 21:16

Unread post by larryhoughton » 30 Jul 2017 6:23

Hi Martin,
I've taken all of your excellent advice. It took a while, but I have everything working nicely now with MS SQL and file stream storage/retrieval of Prolog Fact subsets (as needed) for Prolog processing. Thanks again.
Larry

Post Reply