Monday, November 1, 2010

Type conversion in ParaSail

Allowing for user-defined type conversion is complex, as it is an NxN problem, where you want to allow conversion of N different types to each other, and each pair might involve a different set of operations. ParaSail addresses this problem in the following ways:
  • Allows use of the [[ ... ]] operation, which converts the operand to a universal type.  
    • The user defines which universal type(s) a given type converts to by defining the "to_univ" operator(s).  Once the value has been converted to a universal type, it will be implicitly converted to any other type which defines a "from_univ" operator from that same universal type.  
      • Using a prefix can disambiguate if necessary:  T2::[[T1_Obj]] will convert T1_Obj first to a universal type using T1's "from_univ" operator, and then to T2 using T2's "to_univ" operator.
  •  Allows use of the target type's name as a function name.
    • This will convert between two types that are structurally equivalent (that is, the same module parameters were used in their defining instantiation), but which were distinguished by one or both being defined as new.  For example:
      • type T1 is new Vector<Integer<>> and type T2 is new Vector<Integer<>> define two distinct types because of the use of new, but T2(T1_Obj) and T1(T2_Obj) will convert T1_Obj to type T2, and T2_Obj to type T1, respectively.
    • The target type's name can also convert an object from some source type if the user defines a "convert" operator for either of the two types, and this operator's input and output parameter types match the source and target of the conversion.  Note that this matching might be thanks to the input or output formal being itself parameterized.  For example, the interface Int_Vector below provides a "convert" operator that converts to any other instance of Int_Vector:
            interface Int_Vector<Element is Integer<>> is
               operator "convert"(X : Int_Vector) 
                 -> Result_Type is
                      Int_Vector<Target_Element is Integer<>>;
            end interface Int_Vector;
These capabilities seem to provide enough flexibility for the user to define the desired explicit conversion functions. Note that the only implicit conversion in ParaSail is from a universal type to a type with an appropriate "from_univ" operator.


  1. "Using a prefix can disambiguate if necessary: T2::[[T1_Obj]] will convert T1_Obj first to a universal type using T1's "from_univ" operator, and then to T2 using T2's "to_univ" operator."

    "from_univ" / "to_univ" - other way round, no?

    Are these conversions always 'exception safe'?

  2. There are no run-time exceptions. Any preconditions must be satisfied at compile-time. So the conversion won't be permitted unless you can convince the compiler that the value will be in range for the target type. One way of doing that is to test it, and not do the conversion if it is out of range. The other is for the value to already be "known" to be in range because of the operations that produced it.

    1. I've been wondering: when you say "no exceptions", what do you do about things like division by integer zero? One approach would be to have integer infinities and NaNs (notated 1/0, -1/0, 0/0). Or do you have types like NonZeroInteger?

    2. Many operations in ParaSail have preconditions, which are checked at compile time whenever possible, and at runtime if not. Integer divide by zero has a precondition that the divisor not be zero. That means that integer division by zero fails, either at compile time or runtime, before the operation is attempted.

  3. Okay, it fails, and let's suppose it fails at runtime. Then what? Is the program abandoned?

  4. When parallelism is pervasive, conventional exception handling doesn't make as much sense. In any case, if a precondition (or postcondition) fails at run time, a debugger is invoked, similar to Rust and Pascal.

    The ultimate intent is that the possibility of exceptions is ruled out at compile time (sometimes called proving "AoRTE" -- Absence of Run Time Exceptions). ParaSail does have a means to do something akin to raising an exception for signaling -- essentially expanding on the "trick" of having one thread's actions causing all sibling threads to be terminated, and control to transfer to an outer point.