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
-
- Posts: 11
- Joined: 4 Oct 2016 21:16
-
- VIP Member
- Posts: 354
- Joined: 14 Nov 2002 0:01
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:
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
-
- VIP Member
- Posts: 458
- Joined: 5 Nov 2000 0:01
-
- Posts: 11
- Joined: 4 Oct 2016 21:16
I want my cake and eat it too
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:
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
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
- 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".
- 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
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
-
- VIP Member
- Posts: 354
- Joined: 14 Nov 2002 0:01
The values of domain gmtTimeValue are simply 64 bit numbers. Its declaration in class core is:
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.
Code: Select all
domains
gmtTimeValue = unsigned64.
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
-
- Posts: 11
- Joined: 4 Oct 2016 21:16