ECLiPSe 7.0 Release Notes
Version 7.0 (January 2018)
The main news for this release is the introduction of the multi-engine/multi-thread functionality.
Engines and Threads
An 'engine' is an entity with independent control flow and data areas. In previous versions of ECLiPSe, all code executed in a single, implicit engine. Starting with release 7, engines can be freely created and manipulated.
The essential characteristics of engines are:
- backtracking in one engine does not affect another
- engines can operate in a concurrent or interleaved fashion
- communication between engines is explicit
This opens up a range of new programming techniques, such as
- multithreaded servers
- parallel algorithms
- multiple independent search trees
- engine_create(-Engine, ++Options)
- Create a new ECLiPSe engine
- engine_resume(+Engine, +Term, -Status)
- Resume execution of an engine and return result status
- engine_resume_thread(+Engine, +Term)
- Asynchronously resume execution of an engine (in a separate thread)
- engine_join(+Engine, +Timeout, -Status)
- Wait for an engine to stop running, and return its status
As an alternative interface to the multithreading functionality, we provide library(threads), which implements the functionality defined in ISO/IEC DTR 13211-5:2007.
New Built-In Predicates
Further engine-related functionality
- engine_post(+Engine, +EventGoal)
- Post an event to an engine
- engine_self(-Engine)
- Get a handle of the engine executing the call
- get_engine_property(+Engine, +PropName, -PropValue)
- Obtain properties of an engine, including status
- yield(+ToParent, -FromParent)
- Stop the running engine in the yielded-state, and wait for resume
Array functionality
String functionality
New string operations have been added in coordination with SWI-Prolog.
- atomics_to_string(+Atomics,-String)
- atomics_to_string(+Atomics,+Glue,-String)
- get_string_code(+Index,+String,-Code)
- read_string(+Stream, +SepChars, +PadChars, -Separator, -String)
- string_char(?Index, +String, ?Char)
- string_chars(?String, ?Chars)
- string_code(?Index, +String, ?Code)
- string_codes(?String, ?Codes)
- string_concat(?String1, ?String2, ?String3)
- string_lower(++String, -Upper)
- string_upper(++String, -Upper)
- sub_string(+String, ?Before, ?Length, ?After, ?SubString)
- text_to_string(++Text, -String)
- term_string(?Term, ?String, +Options)
Storage primitives
New storage primitives have been introduced, mainly for convenience in multithreaded applications.
- recorded_count(+RecordHandle,-Count)
- record_wait_append(+RecordHandle,+Value,+Timeout,+Max)
- record_wait_remove(+RecordHandle,-Value,+Timeout)
- shelf_get_and_dec(+ShelfHandle, +Index, -OldValue)
- shelf_inc_and_get(+ShelfHandle, +Index, -NewValue)
- shelf_test_and_set(+ShelfHandle, +Index, +Expected, ?NewValue)
- store_insert(+StoreHandle, ++Key, ?Value)
- store_remove(+StoreHandle, ++Key, -Value)
- store_update(+StoreHandle, ++Key, -OldValue, ?NewValue)
- store_test_and_set(+StoreHandle, ++Key, ++OldValue, ?NewValue)
Names and handles
- getref(+Name,-Term)
- Replaces getval/2 for named references
- setref(+Name,?Term)
- Replaces setval/2 for named references
- is_handle(+Handle,?Class)
- Test for a handle of a particular class, or query a handle's class
- name_to_handle(+Class,+Name,-Handle)
- Get an anonymous handle from a name
- handle_close(+Handle)
- Generic way to close a handle
Mutual exclusion and thread synchronisation
- with_mutex(++Handle, +Goal)
- Equivalent to once(Goal) but with mutual exclusion
- condition_signal(+Handle, +Mode)
- Signal a condition on a handle
- condition_wait(+Handle, +Timeout)
- Wait for a condition to be signaled on a handle
- record_wait_append(+Key,+Value,+Timeout,+Max)
- like recordz/2, but with synchronization
- record_wait_remove(+Key,-Value,+Timeout)
- like erase/2, but with synchronization
Term testing and manipulation
- eval_to_array(?Expr,?Array),
- eval_to_list(?Expr,?List) and
- eval_to_complete_list(?Expr,?List)
- eval_to_list(?Expr,?List) and
- These equate a collection expression with an array or list. They are logical versions of lists:collection_to_list/2.
- term_variables(?Term, -Vars) - semantic change!
- See below.
- term_variables_array(?Term, -VarArray)
- Like term_variables/2, but returning an array.
- term_variables_count(?Term, -VarCount)
- Count of distinct variables.
Arithmetic
The new
scalar product
notation sum(Vector*Vector)
is supported in functional arithmetic
and in arithmetic constraints.
Many constraints that previously required list arguments now also allow arrays and other collection-valued expressions (as specified in eval_to_list/2).
Two new floating-point related arithmetic functions, copysign(+X,+Y) and nexttoward(+X,+Y), have been introduced in accordance with this proposal.
Libraries
New Libraries
- lib(concurrency)
- A library providing higher-level primitives for concurrent/multi-thread programming, implemented using engines.
- lib(best_first_search)
- A library implementing sequential best-first-search in conjunction with propagation-based solvers. It works by recomputing search states.
- lib(ic_mdd) and lib(fd_mdd)
- New extensional constraint implementations, where valid assignments can be specified either via a table of tuples, or via an MDD (multi-valued decision diagram).
- lib(lists_of_structures)
- A library handling operations on lists of structures, in particular where one structure element serves as a key.
New Compatibility Libraries
- lib(clpfd)
- A compatibility wrapper for library(ic) to simplify running of code developed for SICStus Prolog's library(clpfd) and SWI-Prolog's library(clpfd).
- lib(dynamic_attributes)
- Implements Bart Demoen's attributed variable API (as used by hProlog and SWI-Prolog). These are implemented on top of ECLiPSe's native attributed variable functionality, and can be mixed with those.
- lib(eclipse_6)
- A small library containing predicates whose semantics changed in this release, in particular term_variables/2.
- lib(error)
- A utility library to help type checking and raising ISO-Prolog compatible exceptions.
- lib(prolog_extras)
- A library implementing common Prolog predicates that for various reasons we don't want to make into built-in predicates.
- lib(threads)
- A compatibility wrapper that implements a thread-interface as defined in ISO/IEC DTR 13211-5:2007 on top of ECLiPSe's multi-engine functionality.
Contributed Libraries
- lib(lambda)
- A library simplifying the use of higher-order terms.
Library Enhancements
- library(atts)
- Allowed 3rd argument for goal-return to pre_unify handler for attributes. Full implementation of verify_attributes/3 in lib(atts), runs SICStus manual examples without change.
- library(branch_and_bound)
- bb_min/3 has a new option for finding all optimal solutions (solutions:one/all)
- library(calendar)
- added easter_mjd/2
- library(hash)
- added hash_list/2, hash_insert/3
- library(ic)
- added circuit/1 constraint (from build #38).
- library(ic_global_gac)
- reexports extensional constraints from library(ic_mdd).
- library(iso_strict) and library(iso)
- conformance to ISO-Prolog corrigendum 3, and elimination of remaining discrepancies in output spacing. As opposed to previous releases, library(iso) is now also a fully conforming language.
- library(lists)
- added maplist/2 and append/2. Functionality enhancements to collection_to_list/2. flatten/2,3 now also flatten arrays.
- library(swi)
- improved compatibility
Language/Built-In Enhancements
- Array subscripts subscript/3
-
Subscript notation can now extract proper sub-arrays, sub-matrices, etc.
A new symbolic index
*
is recognised as an abbreviation for the range1..N
where N is the array (or dimension) size. Thus, if M is the 2-D matrix[]([](a,b,c,d),[](e,f,g,h))
, thenM[1,2..3]
is the array[](b,c)
, andM[*,2]
is the array[](b,f)
, andM[*,2..3]
is the sub-matrix[]([](b,c),[](f,g))
. - Global flags (get_flag/2)
- A new flag cpu_count indicates the number of logical processors on the machine, which can be helpful in deciding how many threads to create. The new flags default_localsize and default_globalsize determine the default stack sizes for additional engines. The enable_interrupts flag has been removed (interupts are now handled by a separate thread).
- Generalized sort/4 and merge/5
- The sort/4 and merge/5 predicates accept additional order specifications, making number_sort/4 and number_merge/5 obsolete (coordinated with SWI).
- Updated printf/2,3
- Better formatting options for strings, removed restrictions regarding bignums.
- Syntax error handling options
-
The per-module syntax option
syntax_errors_fail
controls whether predicates of the read-family fail or throw an error term when encountering syntax errors. There is also a new read-optionsyntax_errors(quiet|fail|error)
to control this for an individual invocation of read_term/3. - Term writing
-
New options
variable_names(Pairs)
(ISO) andflush(Bool)
in write_term/3. - New DCG implementation
- The Definite Clause Grammar translator (for clauses of the form H-->B) has been revised, maximising compatibility and fixing some long-standing bugs.
Development Support
- Statistics statistics/2 and cputime/1
-
New statistics items:
cputime
(like cputime/1, now gives thread cpu time)dict_gc_countdown
(remaining functor creations until dictionary garbage collection gets triggered)dict_gc_running
(true if a dictionary GC is currently underway)wake_count
(number of delayed goal/constraint wakeups)
- Profiling
- The sampling profiler has been reimplemented and now works on all architectures, including Windows. ECLiPSe has to be started with the new -P command line option (or equivalent) to enable profiling.
Incompatibilities
- Interrupt/Signal handling
- Non-fatal signals are now handled by a dedicated thread, and because of multi-threading, there is no longer a notion of "the interrupted execution". As a result, an interrupt handler can no longer abort a running execution by calling throw/1, but has to be designed to deal appropriately with all the running application threads.
- Term variables
- The term_variables/2 built-in predicate historically returned a variable list in reverse order of left-to-right occurrence in Term. This was unusual, made the predicate non-idempotent, and didn't agree with the ISO Prolog standard. The order has now changed to correspond to the order in which the variables occur in Term in a depth-first, left-to-right traversal. Unfortunately, the change may have subtle effects on programs developed on previous ECLiPSe versions, such as different search trees in constaint programs. The old version can be imported from library(eclipse_6) if necessary.
- Syntax - back-quote character
-
For eclipse_language, we have changed the default character class of the
back-quote character
`
(code point 96) fromsymbol
tolist_quote
. This allows lists of character codes to be written like `abc` (compatible with SWI-Prolog). Applications that use this character for constructing unquoted symbolic atoms (like`=
) will have to use achtab
(0'`,symbol)
declaration to locally restore the original behaviour. - Array slices
-
When
subscript/3
is used to extract an array slice, a sub-array is now
produced instead of a list, e.g.
subscript([](a,b,c,d), [2..3], Slice)
producesSlice = [](b,c)
. This generalises to multi-dimensional arrays. This also affects implicit uses of subscript/3 via array index notation. - Syntax - radix notation
- The syntax option based_bignums is now enabled by default. This means that integers written in radix notation can be larger than the machine's word size, and are not interpreted as two's complements. E.g. 16'ffffffffffffffff is read as 18446744073709551615 rather than -1.
- Syntax - syntax options
-
There are two new syntax options
no_string_concatenation
andeof_is_no_fullstop
, whose effect was previously subsumed byiso_restrictions
. - Term reading
- There is a subtle change in all predicates that read Prolog terms (read/1,2, read_term/2,3, etc): they now leave the stream position pointing to the first blank space character that formed part of the term-terminating fullstop. Previously, this was skipped. The change is motivated by ISO Prolog.
- Term writing - spacing
-
In compact-mode (write-option
compact(true)
, or per-modulesyntax_option(dense_output)
), the term writing built-ins now suppress redundant blank space more aggressively than previously. In non-compact mode, spaces are always printed between operators and their arguments. - Term writing - parentheses
-
When printing terms with prefix functor
-/1
and+/1
, redundant parentheses are no longer printed. Instead, space is inserted if necessary. (This applies only to modules using native ECLiPSe syntax; for modules using ISO syntax, the rules required by standard corrigendum 3 apply). - Handle writing
- Handles are now printed in the new, uniform format $&(kind,id).
Foreign Language Interfaces
The foreign language interfaces have not yet been fully upgraded to
support multiple engines. In the C interface, many of the original
ec_xxx(...)
functions have been replaced by
ecl_xxx(ec_eng_t*, ...)
functions that take an additional
argument which specifies the engine to which the operation applies.
Old (engine-unaware) C code can be compiled by defining the macro
USES_NO_ENGINE_HANDLE before the corresponding include file, i.e.
#define USES_NO_ENGINE_HANDLE #include "eclipse.h"This should work as long as only a single engine is used.
Performance
Performance should generally not be very different from release 6.1. However, there were a number of implementation changes related to the multithread capability, for example related to locking access to shared data structures. If you notice any unexpected effects, please contact eclipse-clp-bugs@lists.sourceforge.net. Other points are:
- Some speed improvements to simple arithmetic.
- The change of the order of the result list in term_variables/2 could have large effects (either way) on performance, if it is used in the computation of the variable list for labeling in constrained search applications. If in doubt, use the compatibility version available in library(eclipse_6).
Supported Architectures
This release is available for the following architectures:
- NEW: Linux/ARM 32-bit (armv7_linux), for Raspberry Pi 2&3
- Linux/x86 (Intel, AMD,...) 32-bit (i386_linux)
- Linux/x86-64 (Intel, AMD) 64-bit (x86_64_linux)
- Mac OS X/Intel 64-bit (x86_64_macosx)
- Windows 32-bit (i386_nt)
- Windows 64-bit (x86_64_nt)