Compile-time usage of objects

Author(s): Angel Fernandez Pineda.

This package is required to enable user code to create objects and manipulate them, as well as loading any needed class.

Usage and interface

  • Library usage:
    Any code which needs to use objects must include the objects package:
        :- module(ModuleName,Exports,[objects]).
    
    You can use objects even if your code is a class. Note that declaring a class does not automatically enables the code to create instances.
        :- class(ModuleName,[],[objects]).
    

    This package enables both static and dynamic usage of objects.

  • New declarations defined:
    use_class/1, instance_of/2, new/2.
  • Other modules used:

Documentation on new declarations

DECLARATION
It establishes an usage relationship between the given file (which is supposed to declare a class) and current source. Usage relationships are needed in order to enable code to create instances of the given class, and to make calls to instances derived from such class.

Since an interface is some kind of class, they may be used within this declaration but only for semantic checking porpouses. Instances will not be derived from interfaces.

use_class/1 is used in the same way as use_module/1.

Usage: :- use_class(ClassSource).

  • Description: Establish usage relationship with ClassSource.
  • The following properties should hold at call time:
    (objects_rt:class_source/1)ClassSource is a valid path to a prolog file containing a class declaration (without .pl extension).

DECLARATION
Statically declares an identifier to be an instance of a given class.

It may be used as new/2 predicate except for:

  • The instance identifier will not be a variable, it must be provided by the user, and must be unique.

  • Instance creation will never fail, even if the constructor fails.

For every statically declared object the given constructor will be called at program startup. Those instances may be destroyed manually, but it is not recommended.

When reloading the involved class from the Ciao toplevel shell. It may destroy statically declared instances, and create them again.

Statically declared instances must be called using a specifically designed module-qualification: ClassName(Object):Goal. For example:

    :- module(example,[main/0],[objects]).
    :- use_class(library(counter)).
    :- cnt instance_of counter(10).

    main :-
         counter(cnt):decrease(1),
         counter(cnt):current_value(X),
         display(X).
But statically written code (only) is allowed to use module-style qualifications as a macro:
    main :-
         cnt:decrease(1),
         cnt:current_value(X),
         display(X).
Notice that dynamically expanded goals such as X=cnt,X:decrease(1) will not work, use X=counter(cnt),X:decrease(1) instead.

Usage: :- instance_of(Object,Constructor).

  • Description: Declares Object to be an instance of the class denoted by Constructor.
  • The following properties should hold at call time:
    (objects_rt:instance_id/1)Object is an unique term which identifies an object.
    (objects_rt:constructor/1)Constructor is a term whose functor matches a class name.

DECLARATION
This declaration has the same effect as instance_of/2.

Usage: :- new(Object,Constructor).

  • Description: Just an alias for instance_of/2.
  • The following properties should hold at call time:
    (objects_rt:instance_id/1)Object is an unique term which identifies an object.
    (objects_rt:constructor/1)Constructor is a term whose functor matches a class name.

Other information

Compile-time errors are restricted to some local analysis. Since there is no type declaration in the Prolog language, there is no posibility to determine whenever a given variable will hold an instance of any class.

However, little semantic analysis is performed. User may aid to perform such an analysis by the usage of run time checks (which are also detected at compile time), or static declarations. For example:

clause(Obj) :- Obj:a_method(334).

O'Ciao may be not able to determine whenever a_method/1 is a valid method for instance Obj, unless some help is provided:

clause(Obj) :- Obj instance_of myclass,Obj:a_method(334).

In such case, O'Ciao will report any semantic error at compile-time.

Most of the run-time errors are related to normal Ciao Prolog module system. Since objects are treated as normal Prolog modules at run time, there is no further documentation here about that stuff.

Error reporting at compile time (objects)

  • ERROR : invalid instance identifier ID: must be an atom

    There is a instance_of/2 or new/2 declaration where first argument ID must be an unique atom, but currently it is not. Statically declared instances needs an identifier to be provided by the user.

  • ERROR : instance identifier ID already in use

    There are two or more instance_of/2 declarations with the same first argument ID. Instance identifiers must be unique.

  • ERROR : invalid use_class/1 declaration: SourceFile is not a class

    Those are the causes for this error:

    • The given SourceFile does not exist, or is not accesible.

    • The given SourceFile is not a Prolog source.

    • The given SourceFile is a valid Prolog source, but it does not declare a class.

  • ERROR : unknown class on ID instance declaration

    The class defined on the instance_of/2 declaration for ID instance has not been loaded by a use_class/1 declaration.

  • ERROR : instance identifier ID is an exisisting Prolog module

    There is an statically declared instance whose identifier may cause interference with the Ciao Prolog module system. Use another instance identifier.

  • ERROR : unknown constructor on ID instance declaration

    The given constructor on the instance_of/2 declaration for ID has not been defined at the corresponding class.

  • ERROR : constructor is needed on ID instance declaration

    No constructor was defined on the instance_of/2 declaration for ID and default constructor is not allowed. You must provide a constructor.

  • ERROR : static instance ID was derived from a different constructor at AnotherModule

    ID has been declared to be an static instance both on AnotherModule and current source, but different constructors were used. The most probable causes for this error are:

    • Occasionally, there is another module using the same instance identifier and it was not noticed by you. Another different identifier may be used instead.

    • It was you intention to use the same object as declared by the other module. In this case, the same constructor must be used.

  • ERROR : invalid first argument in call to new(Arg,_)

    There is a new/1 goal in your code where first argument is not a free variable. For example:

    myobj new myclass

    First argument must be a variable in order to receive a run-time generated object identifier.

  • ERROR : unknown class in call to new(?,Constructor)

    The given Constructor in call to new/2 does not correspond to any used class at current code. The most probable cause of this may be:

    • You forgot to include a use_class/1 declaration in your code.

    • There is a spelling mistake in the constructor.For example:

      :- use_class(myclass).

      foo(X) :- X new mclass.

  • ERROR : can not create an instance from an interface: new(?,Constructor)

    Given Constructor references an interface rather than a class. Instances can not be derived from interface-expanded code.

  • ERROR : unknown constructor in call to new(?,Constructor)

    As the previous error, there is a mistake in the given Constructor. This error is reported when you are trying to call a constructor which was not defined at the corresponding class. Check the class definition to find what is going on.

    Another cause for this error is the incorrect usage of the default constructor. Whenever there are one or more constructors defined at the involved class, you are restricted to chose one of them. This seems that default constructor will be available, if and only if, there are no constructors defined at the involved class.

  • ERROR : call to non-public ID:Goal

    You are trying to call a method which was not declared as public by the class specified in instance_of/2 declaration for ID.

  • ERROR : call to inaccessible predicate at instance ID:Goal

    There is a call to Goal at statically declared instance ID which is unknown or was not declared as public.

  • ERROR : unknown instance ID of class Class at Goal

    There is a call to Goal where involved statically declared instance ID is unknown or is not derived from Class. Check whether it was declared by a instance_of/2 declaration.

  • ERROR : inaccessible attribute Fact at instance ID

    There is an attempt to use ID:Fact but it was not declared as public.

  • ERROR : unknown attribute Fact at instance ID

    There is an attempt to use ID:Fact but it is unknown or it is not an attribute (may be a method).

  • WARNING : invalid call to new(?,_)

    There is a call to new/2 in you code where first argument variable has been determined to hold any other instance. For example:

    foo :- X new myclass,X new otherclass.

    or

    foo(X) :- X instance_of myclass, X new myclass.

    The related call to new/2 will allways fail.

  • WARNING : called Goal is not public at any used class

    There is a call to Var:Goal where Var has not been determined to be compatible with any class. However, Goal is not public at any class specified by the use_class/1 declaration.

    This is a warning (not an error) since Var:Goal may be not related to Object Oriented Programing.

Error reporting at run time (objects)

  • EXCEPTION : instantiation_error( '1st argument must be free variable')

    Calling to new/1 requieres first argument to be a free variable. For example:

    X = this_will_raise_an_exception,X new myclass.

  • EXCEPTION : instantiation_error('class not given')

    You called new/2 using a free variable as second argument.

  • EXCEPTION : instantiation_error(inaccesible_class(Class), from(Module))

    Module tried to create an instance of Class by the ways of new/2, but there is no usage relationship between Module and Class.

  • EXCEPTION : instantiation_error(invalid_constructor( Constructor))

    Constructor was not defined by the corresponding class.