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:

This opens up a range of new programming techniques, such as

The four basic new primitives for this are:
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
Note that the resume/yield model of engine control is a generalisation of the model that was already used previously in the foreign language interface to control ECLiPSe execution.

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

array_sort(+Key,+Order,+Array,-Sorted)
term_variables_array(?Term, -VarArr)

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)
In addition, all storage handles can serve as mutexes and condition variables.

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
Handles are now printed in a uniform format $&(kind,id), where kind is the kind of handle (e.g. stream, record, engine, etc), and id is a unique handle identifier (a number or a string). This print-representation is only for readability, it cannot be used for programming purposes.

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
All storage handles can serve as mutexes and condition variables, and stream handles can serve as mutexes.

Term testing and manipulation

eval_to_array(?Expr,?Array),
eval_to_list(?Expr,?List) and
eval_to_complete_list(?Expr,?List)
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.
All these operations now handle cyclic terms as well.

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 range 1..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)), then M[1,2..3] is the array [](b,c), and M[*,2] is the array [](b,f), and M[*,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-option syntax_errors(quiet|fail|error) to control this for an individual invocation of read_term/3.
Term writing
New options variable_names(Pairs) (ISO) and flush(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) from symbol to list_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 a chtab(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) produces Slice = [](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 and eof_is_no_fullstop, whose effect was previously subsumed by iso_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-module syntax_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:

Supported Architectures

This release is available for the following architectures: